package xman.mssh.spring.aop;

import java.lang.reflect.Method;

import javax.annotation.PostConstruct;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import xman.mssh.spring.SpringBeanDemo;

/*-
 * Spring AOP
 * 通过Pointcut（切点）指定在哪些类的哪些方法上织入横切逻辑
 * 通过Advice（增强）描述横切逻辑和方法的具体织入点（方法前、方法后、方法的两端等）
 * 通过Advisor（切面）将Pointcut和Advice两者组装起来
 * 
 * 有了Advisor的信息，Spring就可以利用JDK或CGLib的动态代理技术采用统一的方式为目标Bean创建织入切面的代理对象了。 
 */
@Component
@Aspect
/*-
 * Advisor
 */
public class DefaultAspectDemo {
    static Logger logger = LoggerFactory.getLogger(DefaultAspectDemo.class);
    
    @PostConstruct
    public void init() {
        logger.info("+++++++++DefaultAspect init++++++++++++");
    }
    
    @Pointcut("execution (* xman.mssh.spring.SpringBeanDemo.*(..))")
    // 括号内的参数是切入点的表达式(返回值<空格>方法选择)
    private void methods() { // methods just the pointcut alias name
    }
    
    /*-
     * Advice
     */
    @Around("methods()")
    public Object aspect(ProceedingJoinPoint pjp) throws Throwable {
        // Object result = pjp.proceed();
        
        String methodName = pjp.getSignature().getName();
        Object[] params = pjp.getArgs();
        Class<?>[] paramClazzs = null;
        if (params != null && params.length > 0) {
            paramClazzs = new Class<?>[params.length];
            int i = 0;
            for (Object param : params) {
                paramClazzs[i++] = param.getClass();
            }
        }
        SpringBeanDemo target = (SpringBeanDemo) pjp.getTarget();
        Method method = target.getClass().getMethod(methodName, paramClazzs);
        logger.info(this.getClass().getName() + " # return type : " + method.getReturnType());

        Object result = target.getClass().getMethod(methodName, paramClazzs).invoke(target, params);
        return result;
    }
    
}
